#ifndef TIMER_WIN32_H
#define TIMER_WIN32_H

#include <Windows.h>


//==============================================================================
// a cpu cycles based timer. must initialize before use
class Timer {
public:
//---- Constructor ----
	explicit Timer(float p_startTimeSeconds = 0.0f):
		m_timeScaleFactor(1.0),
		m_isPaused(true) 
	{
		// initialize just in case it's not done already.
		if(s_cyclesPerSec < 0) {
			Timer::initialize();
		}

		m_timeCycles = secondsToCycles(p_startTimeSeconds);
	} //-----------------------------------------------


//---- Static Methods ----
	// call this function once before creating any timer
	static void initialize() {
		__int64 performanceFreq;
		QueryPerformanceFrequency( (LARGE_INTEGER*)&performanceFreq );
		Timer::s_cyclesPerSec = (float)performanceFreq;
	} //-------------------------------------------------------------



	// gets the number of cycles of cpu time register 
	static inline __int64 readCpuTimerCycles() {
		__int64 cycles;
		QueryPerformanceCounter( (LARGE_INTEGER*) &cycles );
		return cycles;
	} //--------------------------------------------------------------



	// get cycles per second
	static inline float getCyclesPerSecond() {
		if(s_cyclesPerSec < 0) {
			Timer::initialize();
		}

		return s_cyclesPerSec; 
	} //--------------------------------



    static inline double getTimeInRegister() {
        return Timer::readCpuTimerCycles() / Timer::getCyclesPerSecond();
    }
    
    
    
//---- Timer Operations ----
	void pause() {
		m_isPaused = true;
	} //---------------------



	void start() {
		m_isPaused = false;
	} //----------------------



	void resetToZero() {
		m_timeCycles = 0;
	} //------------------------



//---- Getter and Setters ---- 
	__int64 getTimeCycles() const {
		return m_timeCycles;
	} //---------------------------

	void setTimeInSec(float p_seconds) {
		m_timeCycles = secondsToCycles(p_seconds);
	} //-------------------------------

	float getTimeScaleFactor() const {
		return m_timeScaleFactor;
	} //-------------------------

	void setTimeScaleFactor(float p_timeScaleFactor) {
		m_timeScaleFactor = p_timeScaleFactor;
	} //----------------------------------------------

	bool isPaused() const {
		return m_isPaused;
	} //-----------------------------------------------



//---- Update Functions ----
// call every frame to update clocks
	void updateByTime(float p_dt) {
		if(m_isPaused == false) {
			m_timeCycles += secondsToCycles(p_dt * m_timeScaleFactor);
		}
	} //-------------------------------------------------------------



	void updateByCycles(__int64 p_ticksToAdd) {
		if(m_isPaused == false) {
			m_timeCycles += (__int64)(p_ticksToAdd * m_timeScaleFactor);
		}
	} //--------------------------------------------------



private:
//---- Member Variables ----
	// time in cycles
	__int64 m_timeCycles;

	// scale factor when updating time
	float m_timeScaleFactor;

	// true if the timer is paused
	bool m_isPaused;

	// cycles per second, static
	static float s_cyclesPerSec;



//---- Static functions ---- 
	static inline __int64 secondsToCycles(float p_seconds) {
		return (__int64)(p_seconds * s_cyclesPerSec);
	} //----------------------------------------------------
};
//==============================================================================


#endif
